import * as THREE from 'three'
import { huanJing } from '../huanJing/HuanJing.js'
import { GangTi } from './wuTi/GangTi.js'
import { HengXing } from './wuTi/HengXing.js'
import { XingXing } from './wuTi/XingXing.js'
import { FaGuangTi } from './wuTi/FaGuangTi.js'
import { Che } from './wuTi/Che.js'
import { YueShu } from './yueShu/YueShu.js'
import { JiaoLian } from './yueShu/JiaoLian.js'
import { HuaKuai } from './yueShu/HuaKuai.js'
import { WanJia, wanJia } from './wuTi/WanJia.js'
import { cunDang } from '../cunChu/bianLiang.js'
import { gengXinJiHe } from '../gengXin/gengXin.js'
import { ceShiJieJuLi, wanZhengDiZhi } from '../gongJu/gongJu.js'

let changJing = null

/**
 * 场景结构
 * - 实例化网格
 * -    ↓
 * - 单个实例 —— 恒星
 * -               ↓
 * -              行星
 * -               ↓
 * -              物体
 */
class ChangJing {
	shuLiang = 10000 // 恒星数量
	shiLiWangGe = null // 实例网格
	hengXingShuZu = [] // 恒星数组
	dingWeiShuZu = [] // 定位数组
	
	constructor() {
		this.shiLiWangGe = new THREE.InstancedMesh( new THREE.SphereGeometry( 2000, 32, 16 ), new THREE.MeshBasicMaterial(), this.shuLiang );

		changJing = this
	}
	// 生成实例网格星系星空
	shengChengShiLiWangGe() {
		let shiLiShuZu = cunDang.shiLiShuZu
		let instancedMesh = this.shiLiWangGe
		let shuLiang = this.shuLiang
		let changJingBanJing = 3e+6
		let yanSe = new THREE.Color(0xffffff)
		let vec = new THREE.Vector3()
		let mat = new THREE.Matrix4()

		// mat.toArray() // 会卡顿，原因不明

		for ( let i = 0; i < shuLiang; i ++ ) {
			vec.x = Math.random() * 2 - 1;
			vec.y = Math.random() * 2 - 1;
			vec.z = Math.random() * 2 - 1;
			if (i === 0) {
				vec.x = 0;
				vec.y = 0;
				vec.z = 0;
			}
			vec.multiplyScalar( changJingBanJing );
			mat.setPosition(vec)
			instancedMesh.setMatrixAt( i, mat );
			instancedMesh.setColorAt(i, yanSe) // 必须设置颜色 后续才能更改
			// 存储
			shiLiShuZu[i] = {}
			shiLiShuZu[i].bianHuan = instancedMesh.instanceMatrix.array.slice(i * 16, (i + 1) * 16)
			shiLiShuZu[i].yanSe = instancedMesh.instanceColor.array.slice(i * 3, (i + 1) * 3)
		}

		instancedMesh.instanceMatrix.needsUpdate = true;
		instancedMesh.instanceColor.needsUpdate = true;
	}
	// 从存档更新实例
	gengXinShiLiWangGe() {
		let shiLiShuZu = cunDang.shiLiShuZu
		let instancedMesh = this.shiLiWangGe
		let shuLiang = this.shuLiang
		let mat = new THREE.Matrix4()

		for ( let i = 0; i < shuLiang; i ++ ) {
			mat.set(...shiLiShuZu[i].bianHuan)
			mat.transpose() // 存储的列转行
			instancedMesh.setMatrixAt( i, mat );
			instancedMesh.setColorAt(i, new THREE.Color(...shiLiShuZu[i].yanSe))
		}

		instancedMesh.instanceMatrix.needsUpdate = true;
		instancedMesh.instanceColor.needsUpdate = true;
	}
	// 设置单个实例星星
	sheZhiShiLi(suoYin, canShu) {
		let { weiZhi, xuanZhuan, suoFang, yanSe } = canShu
		if (yanSe) {
			this.shiLiWangGe.setMatrixAt(suoYin, yanSe)
			this.shiLiWangGe.instanceColor.needsUpdate = true
		} else {
			let mat = new THREE.Matrix4()
			this.shiLiWangGe.getMatrixAt(suoYin, mat)
			let a = new THREE.Vector3()
			let b = new THREE.Quaternion()
			let c = new THREE.Vector3()
			mat.decompose(a, b, c)
			if (weiZhi) a.copy(weiZhi)
			if (xuanZhuan) b.copy(xuanZhuan)
			if (suoFang) c.copy(suoFang) // matrix4.compose的限制 缩放不能为0
			mat.compose(a, b, c)
			this.shiLiWangGe.setMatrixAt(suoYin, mat)
			this.shiLiWangGe.instanceMatrix.needsUpdate = true
		}
	}
	// 生成行星系统
	shengChengXingXingXiTong(weiZhi) {
		// 恒星
		let hengXing = new HengXing(0xffeedd, 2000)
		hengXing.moXing.position.copy(weiZhi)
		hengXing.mingZi = '太阳' + Math.random().toString(16).slice(2)
		hengXing.fu = this
		// 行星
		const geometry = new THREE.SphereGeometry( 1000, 128, 64 );
		const material = new THREE.MeshStandardMaterial( {color: 0xaa7755 } )
		const sphere = new THREE.Mesh( geometry, material )
		let pengZhuang = sphere.clone()
		pengZhuang.userData.xingZhuang = '球体'
		sphere.position.x = 13000
		let xingXing = new XingXing(sphere, pengZhuang, 1200, 1e+5, 7000, 60 * 60 * 48, 60 * 60 * 10)
		xingXing.mingZi = '地球' + Math.random().toString(16).slice(2)
		xingXing.fu = hengXing
		hengXing.zi.add(xingXing)
		// 卫星
		const geometry2 = new THREE.SphereGeometry( 300, 64, 32 );
		const material2 = new THREE.MeshStandardMaterial( {color: 0xaaaaaa } )
		const sphere2 = new THREE.Mesh( geometry2, material2 )
		let pengZhuang2 = sphere2.clone()
		pengZhuang2.userData.xingZhuang = '球体'
		sphere2.position.x = 2000
		let xingXing2 = new XingXing(sphere2, pengZhuang2, 500, 1e+5, 2000, 60 * 10, 60 * 60)
		xingXing2.mingZi = '月球' + Math.random().toString(16).slice(2)
		xingXing2.fu = xingXing
		xingXing.zi.add(xingXing2)

		return hengXing
	}
	// 加载物体
	jiaZaiWuTi(wuTi, suoYin) {
		let juLi = Infinity
		if (wuTi.fu == this) juLi = ceShiJieJuLi(wuTi.moXing, huanJing.camera)
		else {
			// 未加载时物体为世界坐标系，判断距离需转成父坐标系
			let fuZhu = new THREE.Object3D()
			fuZhu.position.copy(wuTi.moXing.position)
			fuZhu.updateMatrix()
			wuTi.fu.moXing.add(fuZhu)
			juLi = ceShiJieJuLi(fuZhu, huanJing.camera)
			wuTi.fu.moXing.remove(fuZhu)
		}

		if (juLi < wuTi.jiaZaiJuLi) {
			if (wuTi.fu == this) {
				// 加载恒星时隐藏实例星星
				this.sheZhiShiLi(suoYin, { suoFang: new THREE.Vector3(0.001, 0.001, 0.001) })
				
				wanJia.shouGuangHengXing = wuTi
			}

			if (!wuTi.jiaZaiZhuangTai) wuTi.jiaZai()
			
			wuTi.zi.forEach(w => this.jiaZaiWuTi(w))
		} else if (wuTi.jiaZaiZhuangTai) this.xieZaiWuTi(wuTi, suoYin)
	}
	// 卸载物体
	xieZaiWuTi(wuTi, suoYin) {
		if (suoYin !== undefined) this.sheZhiShiLi(suoYin, { suoFang: new THREE.Vector3(1, 1, 1) })
		if (wuTi && wuTi.jiaZaiZhuangTai == true) {
			wuTi.xieZai()
			wuTi.zi.forEach(w => this.xieZaiWuTi(w))
		}
	}
	// 根据距离判断加载恒星
	jiaZaiPanDuan(xiangJiWeiZhi = huanJing.camera.getWorldPosition(new THREE.Vector3())) {
		let shiLiShuZu = cunDang.shiLiShuZu
		let zuiDuanJuLi = Infinity
		let suoYin = 0
		let weiZhi = new THREE.Vector3() // 实例位置
		for (let i = 0; i < this.shuLiang; i++) {
			let shiLiWeiZhi = new THREE.Vector3(shiLiShuZu[i].bianHuan[12], shiLiShuZu[i].bianHuan[13], shiLiShuZu[i].bianHuan[14])
			let juLi = xiangJiWeiZhi.distanceTo(shiLiWeiZhi)
			
			if (juLi < zuiDuanJuLi) {
				if (zuiDuanJuLi != Infinity) this.xieZaiWuTi(this.hengXingShuZu[suoYin], suoYin)
				zuiDuanJuLi = juLi
				suoYin = i
				weiZhi.copy(shiLiWeiZhi)
			} else this.xieZaiWuTi(this.hengXingShuZu[i], i)
		}

		if (!this.hengXingShuZu[suoYin]) {
			let xingXingXiTong = null
			let hengXingCunDang = null
			if (hengXingCunDang = cunDang.shiLiShuZu[suoYin].hengXing) {
				xingXingXiTong = this.duQuWuTi(structuredClone(hengXingCunDang, { transfer: [] }))
			} else {
				xingXingXiTong = this.shengChengXingXingXiTong(weiZhi)
			}

			this.hengXingShuZu[suoYin] = xingXingXiTong
		}

		this.jiaZaiWuTi(this.hengXingShuZu[suoYin], suoYin)
		
		return this.hengXingShuZu[suoYin]
	}
	// 从存档读取生成恒星及其子物体
	duQuWuTi(wuTiCunDang, fu = this, genCunDang) {
		let wuTi = null

		if (genCunDang === undefined) {
			genCunDang = wuTiCunDang
			genCunDang.wuTiJiHe = {}
		}

		const loader = new THREE.ObjectLoader();

		let { moXing, pengZhuangTi } = wuTiCunDang

		moXing = loader.parse(moXing)
		
		if (wuTiCunDang.shiGangTi) {
			pengZhuangTi = loader.parse(pengZhuangTi)

			if (wuTiCunDang.shiFaGuangTi) {
				if (wuTiCunDang.shiHengXing) {
					let { yanSe, banJing } = wuTiCunDang
	
					wuTi = new HengXing(yanSe, banJing)
					
					let { position, quaternion, scale } = wuTi.moXing
					moXing.matrix.decompose(position, quaternion, scale)
				} else {
					let { zhiLiang, yanSe, qiangDu, guangJuLi, yinYingJuLi} = wuTiCunDang

					wuTi = new FaGuangTi(moXing, pengZhuangTi, zhiLiang, yanSe, qiangDu, guangJuLi, yinYingJuLi)
				}
			} else if (wuTiCunDang.shiXingXing) {
				let { yinLiJuLi, jiaZaiJuLi, gongZhuanBanJing, gongZhuanZhouQi, ziZhuanZhouQi } = wuTiCunDang

				wuTi = new XingXing(moXing, pengZhuangTi, yinLiJuLi, jiaZaiJuLi, gongZhuanBanJing, gongZhuanZhouQi, ziZhuanZhouQi)
			} else if (wuTiCunDang.shiChe) {
				let { chiCun } = wuTiCunDang

				wuTi = new Che(moXing, pengZhuangTi, chiCun)
			} else {
				wuTi = new GangTi(moXing, pengZhuangTi, wuTiCunDang.zhiLiang)
			}

			wuTi.bianHao = wuTiCunDang.bianHao
			wuTi.mingZi = wuTiCunDang.mingZi
			wuTi.fu = fu

			genCunDang.wuTiJiHe[wuTi.bianHao] = wuTi

			wuTiCunDang.yueShu.forEach(a => {
				let yueShuCunDang = genCunDang.yueShuJiHe[a]
				let yueShuCanShu = {}
				let yueShuLeiXing = yueShuCunDang.yueShuLeiXing
				let { wuTiA, wuTiB, weiZhiA, weiZhiB, xuanZhuanA, xuanZhuanB } = yueShuCunDang.yueShuCanShu
				wuTiA = genCunDang.wuTiJiHe[wuTiA]
				wuTiB = genCunDang.wuTiJiHe[wuTiB]
				weiZhiA = new THREE.Vector3(...weiZhiA)
				weiZhiB = new THREE.Vector3(...weiZhiB)
				if (xuanZhuanA) xuanZhuanA = new THREE.Quaternion(...xuanZhuanA)
				if (xuanZhuanB) xuanZhuanB = new THREE.Quaternion(...xuanZhuanB)

				if (wuTiA && wuTiB) {
					yueShuCanShu.wuTiA = wuTiA
					yueShuCanShu.wuTiB = wuTiB
					yueShuCanShu.weiZhiA = weiZhiA
					yueShuCanShu.weiZhiB = weiZhiB
					yueShuCanShu.xuanZhuanA = xuanZhuanA
					yueShuCanShu.xuanZhuanB = xuanZhuanB

					let yueShu = null
					if (yueShuCunDang.shiKongZhiTi) {
						if (yueShuCunDang.shiJiaoLian) {
							yueShu = new JiaoLian(wuTiA, wuTiB, weiZhiA, weiZhiB, xuanZhuanA, xuanZhuanB)

						} else if (yueShuCunDang.shiHuaKuai) {
							yueShu = new HuaKuai(wuTiA, wuTiB, weiZhiA, weiZhiB, xuanZhuanA, xuanZhuanB)
						}

						yueShu.suLv = yueShuCunDang.suLv
						yueShu.yueShuFanWei = yueShuCunDang.yueShuFanWei
						yueShu.kuaiJieJian = yueShuCunDang.kuaiJieJian
					} else {
						yueShu = new YueShu(yueShuLeiXing, yueShuCanShu)
					}
				}
			})

			wuTiCunDang.zi.forEach(a => {
				wuTi.zi.add(this.duQuWuTi(a, wuTi, genCunDang))
			})
		}

		return wuTi
	}
	/**
	 * 存储物体
	 * @param {WuTi} wuTi 
	 * @param {Object} genCunDang 根物体存档
	 * @returns 
	 */
	cunChuWuTi(wuTi, genCunDang) {
		let wuTiCunDang = {}

		if (genCunDang === undefined) {
			genCunDang = wuTiCunDang
			genCunDang.yueShuJiHe= {}
		}

		wuTiCunDang.bianHao = wuTi.bianHao
		wuTiCunDang.zhiLiang = wuTi.zhiLiang
		wuTiCunDang.mingZi = wuTi.mingZi

		let { moXing, pengZhuangTi } = wuTi
		let fuZhiMoXing = moXing.clone() // clone的parent为null
		
		fuZhiMoXing.children = moXing.children.filter(a => a.userData.huoQuWuTi?.() == wuTi).map(a => a.clone())
		// 过滤不存档的模型
		let shanChu = []
		fuZhiMoXing.traverse(a => {
			a.children.forEach(b => {
				if (b.userData.buCunDang) shanChu.push(b)
			})
			shanChu.forEach(c => {
				let suoYin = a.children.indexOf(c)
				if (suoYin !== -1) a.children.splice(suoYin, 1)
			})
			shanChu = []
		})

		wuTiCunDang.moXing = fuZhiMoXing.toJSON()

		if (wuTi.shiGangTi) {
			wuTiCunDang.shiGangTi = true
			wuTiCunDang.pengZhuangTi = pengZhuangTi.toJSON()

			if (wuTi.shiFaGuangTi) {
				wuTiCunDang.shiFaGuangTi = true
				if (wuTi.shiHengXing) {
					wuTiCunDang.shiHengXing = true
					wuTiCunDang.yanSe = wuTi.yanSe
					wuTiCunDang.banJing = wuTi.banJing
				} else {
					wuTiCunDang.yanSe = wuTi.yanSe
					wuTiCunDang.qiangDu = wuTi.qiangDu
					wuTiCunDang.guangJuLi = wuTi.guangJuLi
					wuTiCunDang.yinYingJuLi = wuTi.yinYingJuLi
				}
			} else if (wuTi.shiXingXing) {
				wuTiCunDang.shiXingXing = true
				wuTiCunDang.yinLiJuLi = wuTi.yinLiJuLi
				wuTiCunDang.jiaZaiJuLi = wuTi.jiaZaiJuLi
				wuTiCunDang.gongZhuanBanJing = wuTi.gongZhuanBanJing
				wuTiCunDang.gongZhuanZhouQi = wuTi.gongZhuanZhouQi
				wuTiCunDang.ziZhuanZhouQi = wuTi.ziZhuanZhouQi
			} else if (wuTi.shiChe) {
				wuTiCunDang.shiChe = true
				wuTiCunDang.chiCun = wuTi.chiCun
			}

			// 存储约束
			wuTiCunDang.yueShu = []
			wuTi.yueShu.forEach(a => {
				let { wuTiA, wuTiB, weiZhiA, weiZhiB, xuanZhuanA, xuanZhuanB } = a.yueShuCanShu

				let yueShuCunDang = {}
				yueShuCunDang.bianHao = a.bianHao
				yueShuCunDang.yueShuLeiXing = a.yueShuLeiXing
				yueShuCunDang.suLv = a.suLv
				yueShuCunDang.yueShuFanWei = a.yueShuFanWei

				let yueShuCanShu = {}
				yueShuCanShu.wuTiA = wuTiA.bianHao
				yueShuCanShu.wuTiB = wuTiB.bianHao
				yueShuCanShu.weiZhiA = weiZhiA.toArray()
				yueShuCanShu.weiZhiB = weiZhiB.toArray()

				yueShuCanShu.xuanZhuanA = xuanZhuanA?.toArray()
				yueShuCanShu.xuanZhuanB = xuanZhuanB?.toArray()

				yueShuCunDang.yueShuCanShu = yueShuCanShu

				if (a.shiKongZhiTi) {
					yueShuCunDang.shiKongZhiTi = true
					yueShuCunDang.kuaiJieJian = a.kuaiJieJian

					if (a.shiJiaoLian) {
						yueShuCunDang.shiJiaoLian = true
					} else if (a.shiHuaKuai) {
						yueShuCunDang.shiHuaKuai = true
					}
				}

				wuTiCunDang.yueShu.push(yueShuCunDang.bianHao)
				genCunDang.yueShuJiHe[a.bianHao] = yueShuCunDang
			})

			wuTiCunDang.zi = []

			wuTi.zi.forEach(a => {
				wuTiCunDang.zi.push(this.cunChuWuTi(a, genCunDang))
			})
		}

		return wuTiCunDang
	}
	// 存档
	cunDang() {
		// 存储场景数据
		let shiLiShuZu = cunDang.shiLiShuZu

		for (let i = 0; i < this.shuLiang; i++) {
			let shiLi = shiLiShuZu[i]
			let hengXing = this.hengXingShuZu[i]

			if (hengXing) {
				let wuTiCunDang = this.cunChuWuTi(hengXing)
				// 给结构化克隆过滤函数
				wuTiCunDang = JSON.parse(JSON.stringify(wuTiCunDang))

				shiLi.hengXing = wuTiCunDang
			}
		}
		// 存定位
		cunDang.dingWeiShuZu = this.dingWeiShuZu.map(a => a.moXing.position.toArray())
		// 存玩家信息
		cunDang.wanJia.weiZhi = wanJia.moXing.getWorldPosition(new THREE.Vector3()).toArray()
	}
	// 玩家初始化
	chuShiHuaWanJia() {
		// 初始化设置玩家位置
		let dingWei = shengChengDingWei(new THREE.Vector3(11999, 0, 0))
		dingWei.jiaZai()
		this.dingWeiShuZu.push(dingWei)

		let weiZhi = dingWei.moXing.position.clone()
		weiZhi.addScalar(1)
		wanJia.sheZhiPengZhuangTi({ weiZhi })
	}
	// 玩家更新位置
	gengXinWanJia() {
		let weiZhi = new THREE.Vector3(...cunDang.wanJia.weiZhi)
		wanJia.sheZhiPengZhuangTi({ weiZhi })
		// 生成定位
		this.dingWeiShuZu = cunDang.dingWeiShuZu.map(a => {
			let dingWei = shengChengDingWei(new THREE.Vector3(...a))
			dingWei.jiaZai()
			return dingWei
		})
	}
	// 加载场景
	jiaZai() {
		new WanJia()
		wanJia.mingZi = '玩家'
		wanJia.jiaZai()

		if (cunDang.shiLiShuZu.length === 0) {
			this.shengChengShiLiWangGe()

			this.chuShiHuaWanJia()
		} else {
			this.gengXinShiLiWangGe()

			this.gengXinWanJia()
		}

		huanJing.scene.add(this.shiLiWangGe)

		gengXinJiHe.set(this, this.gengXin.bind(this))
	}

	gengXin() {
		this.jiaZaiPanDuan()
		// 1分钟自动存档一次
		let jianGe = Math.trunc(window.performance.now() / 1000) % 60
		if (jianGe === 0) this.cunDang()
	}

	xieZai() {}
}

function shengChengDingWei(weiZhi) {
	// 定位
	const shape = new THREE.Shape();
	shape.moveTo( -1, 1 );
	shape.lineTo( 0, 0.1 );
	shape.lineTo( 1, 1 );
	shape.lineTo( 1, -0.1 );
	shape.lineTo( 0, -1 );
	shape.lineTo( -1, -0.1 );
	shape.lineTo( -1, 1 );
	const extrudeSettings = { steps: 1, depth: 2, bevelEnabled: false };// depth正负为z轴方向
	const geo = new THREE.ExtrudeGeometry( shape, extrudeSettings );
	geo.center()
	let texture = new THREE.TextureLoader().load(wanZhengDiZhi('./tuBiao.png'))
	texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
	texture.center.set(0.5, 0.5)
	texture.rotation = Math.PI
	texture.repeat.set( 0.48, 0.48 ); // 小于1放大纹理
	texture.offset.set(0.26, 0.76)
	texture.anisotropy = 10;
	texture.colorSpace = THREE.SRGBColorSpace;
	let mat = new THREE.MeshStandardMaterial( { map: texture, side: THREE.DoubleSide } )
	let mat1 = new THREE.MeshStandardMaterial( { color: '#acf' } )
	let mesh = new THREE.Mesh( geo, [mat, mat1] )
	mesh.position.copy(weiZhi)
	let pengZhuang = new THREE.Mesh( new THREE.BoxGeometry( 2, 2, 2), new THREE.MeshStandardMaterial() )
	pengZhuang.userData.xingZhuang = '方体'
	let ft = new GangTi(mesh, pengZhuang, 1000)
	ft.mingZi = '定位' + Math.random().toString(16).slice(2)
	ft.jiaZaiJuLi = 20000

	return ft
}

export {
	ChangJing,
	changJing
}
